home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-12-20 | 28.0 KB | 724 lines | [TEXT/MPS ] |
-
- @node Hacking Xconq, Glossary, Design Hints, Top
-
- @chapter Hacking Xconq
-
- Despite its high degree of flexibility, you may decide that you must modify
- the @i{Xconq} program itself. You should know what you are doing;
- @i{Xconq} is designed to be modifiable, but it is not simple code.
- In the past, people have found it easy to make changes,
- but much harder to make them correctly!
-
- @i{Xconq} is designed to be portable to different types of user interfaces.
- It is based on a kernel-interface architecture, where the semantics of
- the game, as documented in the preceding chapters, is part of the kernel,
- while the main program and player interaction are specific to each system.
-
- Don't let interfaces ever set kernel object values directly, always
- go through calls that can be siphoned for networking.
-
- @menu
- * Kernel::
- * Interface::
- * Ideas::
- @end menu
-
- @node Kernel, Interface, Porting Xconq, Porting Xconq
-
- @section Kernel
-
- The kernel is the part of @i{Xconq} shared by all interfaces.
- It does no I/O except to files or for debugging.
-
- Specifically, the kernel supplies these functions:
- @itemize
- @item
- Data structure initialization. (@code{init_data_structures})
-
- @item
- Game module loading and interpretation. (@code{load_game_module})
-
- @item
- Initial player/side setup. (@code{make_trial_assignments})
-
- @item
- Synthesis methods. (@code{run_synthesis_methods})
-
- @item
- Final player/side setup. (@code{make_assignments})
-
- @item
- Game execution. (@code{run_game})
-
- @item
- Implementations of unit actions.
-
- @item
- AI players.
-
- @item
- Help Info (@code{get_help_text})
-
- @item
- Game saving and scorekeeping.
- @end itemize
-
- @subsection Porting the Kernel
-
- The kernel should be restricted to ANSI C, and should avoid or optionalize
- the less common features (like prototypes).
- Although the kernel uses stdio,
- it cannot assume the presence of a console (stdin, stdout, stderr).
-
- You should be careful about memory consumption. In general, the kernel
- takes the attitude that if it was worth allocating, it's worth hanging
- onto; and so the program does not free much storage. Also, nearly all
- of the allocation happens during startup. Since a game may run for a
- very long time (thousands of turns perhaps), it is important not to
- run the risk of exhausting memory at a climactic moment in the game!
-
- @subsection Writing New Synthesis Methods
-
- You can add new synthesis methods to @i{Xconq}.
- This may be necessary if an external program is
- does not exist or is unsuitable.
- Synthesis methods should start out by testing whether or not to run,
- and should never assume that any other method has been run before or
- after, nor that any particular game module has been loaded.
- However, ``tricks'' are usually OK, such as setting a particular global
- variable in a particular module only, then having the synthesis method
- test whether that global is set.
- See the file @code{init.c} for further details.
-
- Synthesis methods that take longer than a second or two to execute
- should generate percent-done info for the interface to use,
- via the function @code{announce_progress}.
- Be aware that most methods will be O(n) or O(n*n) on the
- size of the world or the number of units,
- so they can take much longer to set up
- a large game than a small one.
- Also, @i{Xconq} may be running on a much smaller and slower
- machine than what you're using now.
- (Players will often go overboard and start up giant games too.)
-
- @subsection Writing New Namers
-
- [describe hook and interface]
-
- @subsection Writing New AIs
-
- You can add new types of AIs to @i{Xconq}.
- You would do this to add different strategies as well as
- to add AIs that are programmed specifically for a single game or
- class of games. (This is useful because the generic AI does not
- always understand the appropriate strategy for each game.)
-
- You have to design the object that is the AI's ``mental state''.
- If your AI need only react to the immediate situation, then this
- object can be very simple, but in general you will need to design
- a fairly elaborate structure with a number of substructures.
- Since there may be several AIs in a single game, you should be
- careful about using globals, and since @i{Xconq} games may often
- run for a long time, you should be careful not to consume memory
- recklessly.
-
- @itemize
- @item
- Name.
-
- @item
- Validity function. This runs after modules are loaded, and during player/side
- setup, and decides whether it can be in the given game on the given side.
- [have a chain of fallback AIs, or blow off the game?]
-
- @item
- Game init function. This runs before displays are set up, just in case
- a display examines the AI's state.
-
- @item
- Turn init function. This runs after all the units get their acp and mp
- for the turn, but before anybody actually gets to move.
-
- @item
- Unit order function. This gets run to decide what the unit should do.
- Usually it should be allowed to follow its plan.
- [do separate fns for before and after plan execution?]
-
- @item
- Event reaction functions. [how many?]
-
- @end itemize
-
- Note that these functions have very few constraints, so you can write them
- to work together in various ways. For instance, an AI can decide whether
- to resign once/turn, once/action, or once for each 4 units it moves, every
- other turn.
-
- @node Interface, Ideas, Kernel, Porting Xconq
-
- @section Interface
-
- The player interface is how actual players interact with the game.
- It need not be graphical or even particularly interactive,
- in fact it could even be a network server-style interface!
- However, this section will concentrate on the construction
- of interactive graphical interfaces.
-
- An interface is always compiled in, so it has complete access to the
- game state. However, if your version of @i{Xconq} has any networking
- support, the interface should not modify kernel structures directly,
- but should instead use kernel routines. The kernel routines will
- forward any state modifications to all other programs participating
- in a game, so that everybody's state remains consistent.
-
- A working interface must provide some level of capability in each
- of these areas:
-
- @itemize
- @item
- Main program.
- The interface includes the main application and any
- system-specific infrastructure, such as event handling.
-
- @item
- Interpretation of startup options.
- This includes choice of games, variants, and players.
-
- @item
- Display of game state.
- This includes both textual and graphical displays,
- both static and dynamic.
-
- @item
- Commands/gestures for unit tasks and actions,
- and for general state modifications.
-
- @item
- Display update in response to state changes.
-
- @item
- Realtime progress.
- Some game designs require the interface
- to support realtime.
- @end itemize
-
- @subsection Main Program
-
- The interface actually provides the ``main program'' for
- @i{Xconq}; this allows maximum flexibility in adapting
- to different environments.
-
- Once a game is underway, the interface is in a sense self-contained,
- needing only to call @code{run_game} periodically to keep the
- game moving along. @code{run_game} takes one argument which can
- be -1, 0, or 1. If 1, then one unit gets to do one action, then
- the routine returns. If 0, the calculations are gone through, but
- no units can move. If -1, then all possible units will move before
- @code{run_game} returns. This last case is not recommended for interactive
- programs, since moving all units in a large game may take a very long
- time; several minutes sometimes.
-
- [When networking, all kernels must call with same values...]
-
- @subsection Startup Options
-
-
- @subsection Progress Indication
-
- Some synthesis methods are very slow, and become even
- slow when creating large games, so the kernel will announce a slow process,
- provide regular updates, and signal when the process is done. The interface
- should display this in some useful way. In general, progress should always
- be displayed, although one could postpone displaying anything until after
- the first progress update, calculate an estimated time to completion, and
- not display anything if that estimate is for less than a few seconds.
- However, this is probably unnecessary.
-
- @subsection Feedback and Control
-
- The interface should provide visible feedback for every successful unit
- action initiated directly by the player, but it need not do so for failures,
- unless they are serious. It is better to prevent nonsensical input,
- for instance by disabling menus and control panel items. Simple interfaces
- such as for character terminals will have to relax these rules somewhat.
-
- Interfaces should enable/disable display of lighting conditions.
-
- @subsection Textual Displays
-
- Text can take a long time to read, and can be difficult to provide
- in multiple human languages. (What, you thought only English speakers
- played @i{Xconq}? Think again!)
- Therefore, text displays in the interfaces should be as minimal as
- possible, and derive from strings supplied in the game design,
- since they can be altered without rebuilding the entire program.
-
- @subsection Display Update
-
- Usually the interface's display is controlled by the player,
- but when @code{run_game} is executing, it will frequently change
- the state of an object in a way that needs to be reflected in the
- display immediately. Examples include units leaving or entering
- a cell, sides losing or winning, and so forth. The interface
- must define a set of callbacks that will be invoked by the kernel.
-
- @code{update_cell_display(side, x, y, rightnow)}
-
- [introduce area (radius or rect) update routines?]
-
- @code{update_side_display(side, side2, rightnow)}
-
- @code{update_unit_display(side, unit, rightnow)}
-
- [etc]
-
- Each of these routines has a flag indicating whether the change may be
- buffered or not.
- To ensure that buffered data is actually onscreen,
- the kernel may call @code{flush_display_buffers()}.
-
- These may or may not be called on reasonable sides, so the
- interface should always check first that @code{side} actually
- exists and has an active display.
- [If side has a "remote" display, then interface has to forward??
- No, because remote copy of game is synchronized and does own
- update_xxx calls more-or-less simultaneously]
-
- Note that this is as much as the kernel interests itself in displays.
- Map, list, etc drawing and redrawing are under the direct control
- of the interface code.
-
- @subsection Types of Windows and Panels
-
- @i{Xconq} is best with a window-style interface, either tiled
- or overlapping. Overlapping is more flexible, but sometimes
- complicates understanding as players try to arrange them usefully.
- In the following discussion, "window" will refer to a logically
- unified part of the display, which can be either a window or a panel
- in some larger window.
-
- The centerpiece window should be a map display.
- This will be the most-used window,
- since it will typically display more useful information
- than any other window.
- This means that it must also exhibit very good performance.
-
- When a game starts up, the map display should be centered
- on one of the player's units, preferably one close to the
- center of all the player's units.
-
- Another recommended window a list of all the sides and where
- they stand in both the current turn and in the game as a whole.
-
- Overall status of side rules:
-
- all grayed: out of game
-
- grayed and x-ed out: lost
-
- ???: won
-
- Progress bar rules:
-
- missing: no units or no ai/no display
-
- grayed frame: no acting units
-
- empty solid frame: all acted
-
- part full, black: partly acted
-
- part full, gray: finished turn
-
- @subsection Imaging
-
- Imaging is the process of drawing pictorial representations.
- Not every interface needs it, for instance the curses interface
- is limited to drawing two ASCII characters in a cell,
- which is the extent of its imaging.
- However, full-color bitmapped displays need more attention
- to the process of getting an image onscreen.
-
- No graphical icon should be drawn smaller than about 8x8, unless it's
- a text character drawn in two contrasting colors.
-
- Interfaces should cache optimal displays for each mag, not search
- for best image each time.
-
- Could allow 1-n "display variants" for all images, and for each orientation of
- border and connection.
-
- Imaging variations can be randomly selected by UI,
- but must be maintained so redraws are consistent.
-
- Could allow the 64 bord/conn combos as single images, also advantage
- that all will be drawn at once.
-
- @subsection Designer's Tools
-
- An interface is not required to provide any sort of online
- designing tools, or even to provide a way to enable the
- special design privileges. Nevertheless, minimal tools
- can be very helpful, and you will often find that they are
- helpful in debugging the rest of the interface, since you
- can use them to construct test cases at any time.
-
- A basic set of design tools should include a way to enable
- and disable designing for at least one side, a command to
- create units of a given type, and some sort of tool to set
- the terrain type at a given location. A full set would
- include ``painting'' tools for all area layers, including
- geographical features, materials, weather, side views,
- and so forth - about a dozen in all.
-
- A least one level of undo for designer actions is very
- desirable, although it may be hard to implement.
- A useful rule for layers is to save a layer's previous
- state at the beginning of each painting or other modification
- action, when the mouse button first goes down.
-
- The designer will often want to save only the part of the game
- being worked on, for instance only the units or only the terrain.
- The "save game" action should give designers a choice about
- what to save. For units particularly, the designer should be
- able to save only some properties of units. The most basic
- properties are type, location, side, and name/number.
- The unit id should not be saved by default, but should have
- its own option (not clear why).
-
- Note that because game modules are textual and can be
- moved easily from one system to another, it is entirely
- possible to use one @i{Xconq} (perhaps on a Mac) to design
- games to be played on a Unix box under X11, or vice versa.
- Transferring the imagery is more difficult, although there
- is some support for the process.
-
- @subsection Porting and Multiple Interfaces
-
- In theory, it is possible to compile in multiple interfaces,
- but they would have to be multiplexed appropriately and not
- conflict anywhere in the address space.
- Sometimes this is intrinsically impossible;
- how could you compile the Mac and X interfaces into the same
- program, and would the result be a Mac application, a Unix program,
- or what?
-
- The kernel/interface architecture could however be exploited to build
- a true server/client @i{Xconq},
- by building an ``interface'' that manages IPC connections
- and calling this the server, and then writing separate interface
- programs that translate data at the other end of the IPC connection
- into something that a display could use.
- My previous attempt at this was very slow and buggy,
- though, so this is not necessarily an easy thing to write.
- The chief problem is in keeping the client's view of thousands
- of interlinked objects (units, sides, cells, and so forth)
- consistent with the server.
- Most existing server/client games work by either restricting
- the state to a handful of objects,
- or by only handing the client display-prepared data
- rather than abstract data,
- or by reducing the update interval
- to minutes or hours.
-
- @subsection Guidelines and Suggestions
-
- Although as the interface builder, you are free to make it work in any
- way you like, there are a number of basic things you should do.
- Some of these are general user interface principles, others are specific
- to @i{Xconq}, usually based on experiences with the existing interfaces.
- Applying some of these guidelines will require judicious balancing between
- consistency with the different version of @i{Xconq} and consistency with
- the system you're porting to.
-
- [following items should be better organized, moved in with relevant sections]
-
- There should always be some sort of "what's happening now" display
- so player doesn't wonder about apparently dead machine.
-
- Interfaces should ensure stability of display choices
- if random possibilities, so need to cache local decisions about
- appearance of units if multiple images to choose from, choice of
- text messages, etc.
-
- Rules of Interaction:
- 1. Player can get to any unit in any mode.
- 2. Any player can prevent a turn from completing(/progressing?),
- unless a hard real limit is encountered.
- 3. All players see each others' general move/activity state, modes, etc.
- 4. Players can "nudge" each other.
- 5. Real time limits can be set for sides, turns, and games, both by players
- and by scenarios.
-
- Both standard and nonstandard variants should vanish from dialog boxes
- if irrelevant to a selected game.
-
- Player should be able to click on a desired unit or image, and effectively
- say "take this", either grabs directly or else composes a task to approach
- and capture.
-
- Side lists should be adjusted to accommodate all scores being kept.
-
- Allow for some kind of "face" or group of faces/expressions for a side,
- so get a barbarian's face to repn a side instead of generic.
- Could have interface generate remarks/balloons if face clicked on,
- perhaps a reason for feelings, slogan, citation of agreement or broken
- agreement, etc.
- Need 5 faces for hostile, unfavorable, neutral, favorable, friendly/trusting.
-
- Unit closeups should be laid out individually for each type, too much
- variability to make a single format reasonable.
-
- Add option where game design can specify use or avoidance of masks
- with unit icons.
-
- Player could escape a loss by saving a game, then discarding save.
- Mplayers could register suspicion when player saves then quits -
- "You're not trying to cheat, are you?" - but can't prevent this.
-
- All interfaces should be able to bring up an "Instructions" window
- that informs player(s) about the current game, includes xrefs to all
- game design info. Restrict help to generic and interface info only.
-
- Graph display should graphing of various useful values, such as amounts
- of units and materials over time, attitudes of sides, combat, etc.
- Maximal is timeline for all sides and units, usually too elaborate but
- allow tracking movement for some "important" units. Note that move
- actions may be recorded anyway.
-
- Make specialized dialog for agreements, put name on top, then scrolling list of
- terms, then signers, then random bits (public/secret, etc). Use for proposals
- also, so allow for "tentative" signers, desired signers who have not looked at
- agreement. Be able to display truth of each term, but need test to know when
- a side can know the truth of a term?
-
- A quit cmd can always take a player out of the game, but player may have
- to agree to resign. Player can also declare willingness to quit or draw
- without actually doing so, then resolution requires that everybody agree.
- If quitting but others continuing on, also have option of being a
- spectator. Could have notion of "leaving game without declaring entire
- game a draw" for some players.
- Allow for a timeout and default vote in case some voters have disappeared
- mysteriously.
- Must never force a player to stay in.
- Add a notion of login/logout so a side can be inactive but untouchable,
- possibly freezes entire game if a side is inactive.
- 1. if one player or no scoring
- confirm, then shut player down
- if one player, then shut game down
- 2. if side is considered a sure win (how to tell? is effectively a win
- condition then) or all sides willing to draw
- confirm, take side out, declare a draw, shut player down
- 3. if all sides willing to quit
- take entire game down
- 4. ask about resigning - if yes,
- resign, close display, keep game running
- if no, ask if willing to quit and/or draw, send msg to other sides
- Kernel support limited to must_resign_to_quit(side), similar tests.
-
- Interfaces should have a ``wake up dummy'' button that can be used by players
- who have finished their turn, to prod other players not yet done.
-
- Commands that are irrelevant for a game ought to be grayed out in
- help displays, and error messages should identify as completely invalid
- (or just not do anything, a la grayed Mac menu shortcuts).
-
- Prefixed number args should almost always be repetitions.
-
- Should be able to drag out a route and have unit follow it (user input
- of a complete task sequence).
-
- Hack formatting so that variable-width fonts usually work reasonably.
-
- Add xref buttons to various windows to go to other relevant windows and
- focus in.
-
- Draw partial cells around edges of a window, to indicate that the world
- continues on in that direction.
-
- The current turn or date should be displayed prominently and be visible
- somewhere by default.
-
- Add some high-level verbs as commands ("assault Berlin", "bomb London until
- destroyed").
-
- Interface needs to draw *only* the terrain in edge cells.
- For cells along an edge with a bg gray (a la Mac), draw a heavy edge
- between cell and nothingness, diff from cell and unseen cells.
-
- Could draw grid by blitting large light pattern over world, do by inverting
- so is easy to turn on/off. Do grids by changing hex size only in
- unpatterned color?
-
- Draw large hexagon or rect in unseen-color after clearing window to bg
- stipple (if unseen-color different). Polygon should be inside area
- covered by edge hexes, so unseen area more obvious.
- Make large unseen-pattern that includes question marks?
-
- Don't draw outline boxes at mags that would let them get outside the hex.
-
- If dating view data, allow it to gray out rather than disappear entirely.
- Could even have a "fade time" for unit images...
-
- Even if display is textual, use red text (and other colors) to indicate
- dangerous conditions.
-
- If picture not defined for a game, use some sort of nondescript image
- instead of leaving blank. (small "no picture available" for instance,
- like in yearbooks)
-
- Next/prev unit controls should change map focus, even if screen
- unaffected.
-
- In general, ability to "select" a unit implies ability to examine,
- but not control. Control implies ability to select, however.
-
- Connections may need to be drawn differently in each of the two hexes
- they involve, such as straits connecting to a sea.
- (what is this supposed to mean?)
-
- To display night, could invert everything (b/w) or do 25/50% black (color)
- (let game set, so some games could be all-black at night, nothing visible)
- (have day/night coverage for each utype?)
-
- If cell cramped for space, show only one material type at a time,
- require redraw to show amounts of a different type.
-
- Draw time remaining both digitally and as hourglass, for all time
- limits in effect.
-
- Could tie map to follow a specified unit (or to flip there quickly
- a la SimAnt).
-
- Have a separate message window from notices, allow broadcasting w/o
- specific msg command? (a "talk" window)
-
- To display elevation, use deep blue -> light gray -> dark brown progression,
- maybe also contour lines?
- To draw contour lines, for each hex, look at each adj hex. If on other
- side of contour's elev, compute interpolated point (in pixels) and save
- or draw a line to (one or both of the two) adj hex borders if they also
- have the contour line pass through. Guaranteed that line is part of
- overall contour line. Cheaper approach doesn't interpolate, just draws
- to midpoint of hex border (probably OK for small mags).
- Could maybe save contour lines once calculated (at each mag, lots of mem).
-
- Redraw hexes exposed when a unit with a legend moves.
- Truncate or move legend if would overlap some other unit/legend.
-
- Put limits on the number of windows of each type, set up so will reuse
- windows, except for ones that are "staked down".
-
- Fix border removal so inter-hex boundary pixels are cleaned up also.
-
- Need a specialized window or display to check on current scores
- (showing actual situation vs what's still needed).
- (Show both scorekeepers actually in force, as well as the others.)
- Side display could also display scores relevant to that side.
-
- Every unit plan display should have a place to record notes and general
- info about the unit, add a slot to units also. Use in scenarios.
-
- Need a command for when a player can explicitly change the self-unit.
-
- Players should be able to rename any named object. The interface should
- also provide a button or control to run any namer that might be available
- to the unit.
-
- @subsection Versioning Standards
-
- In version @var{7.x.y}, @var{x} should change only
- when some documented user-visible aspect of @i{Xconq} changes,
- whether in the interface or kernel.
- @var{y} is reserved for bug-fix releases, which can include
- the implementation of features deliberately left unimplemented.
-
- @section Pitfalls
-
- This chapter would not be complete without some discussion of the traps
- awaiting the unwary hacker.
- The Absolute Number One Hazard in hacking @i{Xconq} is to introduce
- code that does not work for @emph{all} game designs.
- It is all too easy to assume that, for instance, unit speeds are always
- less than 20, or airbases can only be built by infantry, or that worlds
- are always randomly-generated.
- These sorts of assumptions have caused no end of crashes.
- Code should test preconditions, especially for dynamically-allocated
- game-specified objects, and it should be tested using the various
- test scripts in the test directory.
-
- The number two pitfall is to not account for all the possible interfaces.
- Not all interfaces have a single ``current unit'' or map window,
- and some communicate with multiple players or over a network connection.
-
- You should not assume that your hack is generally valid until you have
- tested it against everything in the library and test directories.
- The @code{test} directory contains scripts that will be useful for this,
- at least to Un*x hackers.
-
- Another pitfall is to be sloppy about performance. An algorithm that works
- fine in a small world with two sides and 50 units may be painfully slow
- in a large game. Or, the algorithm may allocate too much working space
- and wind up exhausting memory (this has happened).
- You should familiarize yourself with the algorithms already used in @i{Xconq},
- since they have already been debugged and tuned, and many have been written
- as generically useful code (see @code{world.c} for instance).
-
- If your new feature is expensive, then define an efficient have_xxx()
- test that can be called from relevant places.
-
- If time/effort to do action is > length of game, then interface
- can disable that action permanently.
-
- Use moving bar or gray under black to indicate reserve/asleep units.
-
- @section Rationale and Future Directions
-
- This is where I justify everything I've done.
-
- Please note that although @i{Xconq} has considerable power,
- its design was expressly limited to a particular class of two-dimensional
- board-like strategy games, and that playability is emphasized over
- generality. For instance, I avoided the temptation to include a
- general-purpose language, since it opens up many difficult issues
- and makes it much harder for game designers to produce a desired
- game (after all, if game designers wanted to use a general-purpose
- programming language, they could just write C code!). Similarly,
- full 3D, realtime maneuvering, continuous terrain, and other such goodies
- must await the truly ultimate game system.
-
- The real problem with a general-purpose language is that although
- everything is possible, nothing is easy. Many ``adventure game
- writing systems'' have fallen into this trap; they end up being
- poor reimplementations of standard programming languages, and the
- sole support for adventure gaming amounts to a small program
- skeleton and a few library functions. It would have been easier
- just to start with a pre-existing language and just write the
- skeleton and libraries!
-
- @i{Xconq}, on the other hand, provides extensive optimized support
- for random game setup, large numbers of units, game save/restore,
- computer opponents, and many other facets of a game.
- Game designers don't have to deal with
- the subleties of fractal terrain synthesis, or the ordering of
- terrain effects on units, or how to tell the computer opponents
- that airbases are sometimes good for refueling but never any
- good for transportation, or the myriad of other details that
- are wired into @i{Xconq}.
- In fact, a complete working game can be set up with less than
- a half-page of GDL.
-
- Even so, the current @i{Xconq} design allows for several layers
- of extensibility, as was described earlier in this chapter.
-
- There are also several major areas in which @i{Xconq}
- could be improved.
-
- Tables should be supplemented with general formulae, although
- such formulae will complicate AIs' analyses considerably,
- since tables are much easier to scan.
-
- Currently everything is based on a single area of a single world.
- This could be extended to multiple areas in the world, perhaps
- at different scales, as well as to multiple worlds.
-